<html>

<head>
    <title>File Upload</title>
</head>

<body>
    <div>
        <h1>File upload</h1>
        <input type="file" id="file-uploader">

        <div id="feedback"></div>

        <label id="progress-label" for="progress"></label>
        <progress id="progress" value="0" max="100"> </progress>
    </div>
</body>

<script>
    const CHUNK_SIZE = 1024 * 1024;
    // 切片
    class FileChunk {
      constructor(chunk, fileName, start, end, total) {
        this.chunk = chunk;
        this.fileName = fileName;
        // 切片起始位置
        this.start = start;
        // 切片结束位置
        this.end = end;
        // 文件总大小
        this.total = total;
        // 切片 Hash 值
        this.chunkName = '';
        this.fileHash = '';
        // 索引
        this.index = 0;
        // 文件切片数
        this.chunkNum = 0;
        // 文件状态 'READY', 'UPLOADING', 'SUCCESS', 'ERROR'
        this.status = 'READY';
      }

      toFormData() {
        const formData = new FormData();
        formData.append('chunk', this.chunk);
        formData.append('fileHash', this.fileHash);
        formData.append('chunkName', this.chunkName);
        formData.append('chunkNum', this.chunkNum);
        formData.append('start', this.start);
        formData.append('end', this.end);
        formData.append('total', this.total);
        formData.append('index', this.index);
        formData.append('fileName', this.fileName);

        return formData;
      }
    }

    // 生成文件切片
    function createFileChunk(file, blockSize = CHUNK_SIZE) {
      const fileChunkList = [];
      const { name, size } = file;
      let cur = 0;

      while (cur < size) {
        let end = cur + blockSize;

        if (end > size) {
          end = size;
        }

        fileChunkList.push(
          new FileChunk(file.slice(cur, end), name, cur, end, size),
        );

        cur += blockSize;
      }

      const chunkNum = fileChunkList.length;

      fileChunkList.forEach((chunkFile, index) => {
        // 这里不生成 Hash 值，会严重阻塞进程
        chunkFile.index = index;
        chunkFile.chunkNum = chunkNum;
        chunkFile.chunkName = chunkFile.fileName + '_' + index;
      });

      return fileChunkList;
    }

    const feedback = document.getElementById('feedback');
    const progress = document.getElementById('progress');
    const fileUploader = document.getElementById('file-uploader');


    const reader = new FileReader();

    fileUploader.addEventListener('change', (event) => {
        const files = event.target.files;
        const file = files[0];
        fileChunkList = createFileChunk(file);
        for (let i = 0; i < fileChunkList.length; i++) {
            let item = fileChunkList[i];
            console.log('fileName:', item.fileName);
            console.log('chunkNum:', item.chunkNum);
            console.log('chunkName:', item.chunkName);
            console.log('start:', item.start);
            console.log('end:', item.end);
            console.log('total:', item.total);
            console.log('index:', item.index);
            console.log('status:', item.status);
            console.log('------------------');
        }
        reader.readAsDataURL(file);

        reader.addEventListener('progress', (event) => {
            if (event.loaded && event.total) {
                const percent = (event.loaded / event.total) * 100;
                progress.value = percent;
                document.getElementById('progress-label').innerHTML = Math.round(percent) + '%';

                if (percent === 100) {
                    let msg = `<span style="color:green;">File <u><b>${file.name}</b></u> has been uploaded successfully.</span>`;
                    feedback.innerHTML = msg;
                }
            }
        });
    });

</script>

</html>